/* Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * This file is a part of the CANN Open Software.
 * Licensed under CANN Open Software License Agreement Version 1.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 * ===================================================================================================================*/

#ifndef GRAPH_ASCEND_IR_H
#define GRAPH_ASCEND_IR_H

#include <string>
#include <memory>
#include "attr_store.h"
#include "graph/compute_graph.h"
#include "graph/ascend_ir/expression.h"
#include "graph/node.h"
#include "graph/anchor.h"
#include "debug/ge_util.h"
#include "graph/utils/op_desc_utils.h"
#include "external/graph/operator.h"
#include "graph/ascend_ir/ascend_ir_check.h"

namespace ge {
namespace {
constexpr int64_t kIdNone = -1;
}

struct Axis {
  using Type = enum : int32_t {
    AXIS_TYPE_ORIGINAL,
    AXIS_TYPE_BLOCK_OUTER,  // outer axis after split by multicore
    AXIS_TYPE_BLOCK_INNER,  // inner axis after split by multicore
    AXIS_TYPE_TILE_OUTER,   // outer axis after split by one core
    AXIS_TYPE_TILE_INNER,   // inner axis after split by one core
    AXIS_TYPE_MERGED,
    AXIS_TYPE_INVALID
  };

  int64_t id{-1};        // axis id
  std::string name;  // axis name
  Type type{AXIS_TYPE_INVALID};
  bool bind_block{false};
  ge::expression::ExpressionPtr size;
  int32_t align{-1};
  std::vector<int64_t> from;
  uint64_t split_pair_other_id{UINT64_MAX};
  bool allow_oversize_axis{false};
  bool allow_unaligned_tail{false};
  std::pair<int64_t, int64_t> value_range = {-1, -1};
};
using AxisPtr = std::shared_ptr<Axis>;
using AxisId = int64_t;

struct Optional {
  uint32_t idx{UINT32_MAX};
  std::string name;
  std::string data_type;
  std::string min_value;
  std::string max_value;
};
using OptionalPtr = std::shared_ptr<Optional>;
enum class TransType : int64_t {
  kSplit = 0,
  kMerge,
  kValid
};
struct OneTransInfo {
  TransType trans_type;
  std::vector<AxisPtr> src_axis;
  std::vector<AxisPtr> dst_axis;
};
struct DiffAxesInfo {
  std::vector<AxisId> add_axes;
  std::vector<AxisId> del_axes;
};
using TransInfoRoadOfGraph = std::vector<OneTransInfo>;
using View = std::tuple<std::vector<int64_t>,
                        std::vector<ge::expression::ExpressionPtr>,
                        std::vector<ge::expression::ExpressionPtr>>;

template<typename T>
std::string ViewMemberToString(const std::vector<T> &vec) {
  std::string result = "[";
  for (size_t i = 0; i < vec.size(); ++i) {
    if constexpr (std::is_same_v<T, ge::expression::ExpressionPtr>) {
      result += (vec[i] ? vec[i]->Str() : "null");
    } else {
      result += std::to_string(vec[i]);
    }
    if (i < vec.size() - 1) {
      result += ", ";
    }
  }
  result += "]";
  return result;
}

inline std::string ViewToString(const View &view) {
  const auto &axis = std::get<0>(view);
  const auto &repeats = std::get<1>(view);
  const auto &strides = std::get<2>(view);

  std::string result = "{ axis: " + ViewMemberToString(axis) +
      ", repeats: " + ViewMemberToString(repeats) +
      ", strides: " + ViewMemberToString(strides) +
      " }";
  return result;
}

enum class ComputeType : int32_t {
  COMPUTE_DATA,
  COMPUTE_REDUCE_DATA,
  COMPUTE_WORKSPACE,
  COMPUTE_LOAD,
  COMPUTE_STORE,
  COMPUTE_REDUCE_STORE,
  COMPUTE_ELEWISE,
  COMPUTE_BROADCAST,
  COMPUTE_REDUCE,
  COMPUTE_TRANPOSE,
  COMPUTE_INVALID,
};

enum class ComputeUnit : int32_t {
  UNIT_NONE,
  UNIT_MTE1,
  UNIT_MTE2,
  UNIT_MTE3,
  UNIT_SCALAR,
  UNIT_VECTOR,
  UNIT_CUBE,
  UNIT_INVALID,
};

enum class ApiType : int32_t {
  API_TYPE_BUFFER,
  API_TYPE_COMPUTE,
  API_TYPE_INVALID,
};

struct ApiInfo {
  ApiType type = ApiType::API_TYPE_INVALID;
  ComputeUnit unit = ComputeUnit::UNIT_INVALID;
};

struct HintComputeType {
  ComputeType compute_type = ComputeType::COMPUTE_INVALID;
};

struct SchedInfo {
  int64_t exec_order{-1};
  int64_t sub_exec_order{-1};
  std::vector<int64_t> axis;
  int64_t loop_axis{-1};
  std::vector<int64_t> initial_axis;
};

struct AscNodeAttr : public ge::AttrGroupsBase {
  SchedInfo sched;
  ApiInfo api;
  HintComputeType hint;
  AscNodeAttr() = default;
  ~AscNodeAttr() override = default;
  static AscNodeAttr &GetAttrGroup(ge::Operator &op);
  AttrGroupsBase *CreateNew() override;
};

struct AscDataNodeAttr : public AscNodeAttr {
  ~AscDataNodeAttr() override = default;
  static AscDataNodeAttr &GetAttrGroup(ge::Operator &op) {
    auto opdesc = ge::OpDescUtils::GetOpDescFromOperator(op).get();
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(opdesc);
    auto attr_group = opdesc->GetOrCreateAttrsGroup<AscDataNodeAttr>();
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(attr_group);
    return *attr_group;
  };
  AttrGroupsBase *CreateNew() override {
    return new(std::nothrow) AscDataNodeAttr(*this);
  };
  int64_t index{-1};
  std::vector<std::vector<int64_t>> axis_continuous_map;
  ge::Format format;
};

struct AscGraphAttr : public ge::AttrGroupsBase {
  int64_t tiling_key = -1;
  std::vector<AxisPtr> axis;
  std::vector<OptionalPtr> optional;
  TransInfoRoadOfGraph trans_info_road;
  AttrGroupsBase *CreateNew() override;
};
enum class AllocType : int32_t { ALLOC_TYPE_GLOBAL, ALLOC_TYPE_L1, ALLOC_TYPE_L2, ALLOC_TYPE_BUFFER, ALLOC_TYPE_QUEUE };

enum class MemHardware : int32_t {
  MEM_HARDWARE_GM,
  MEM_HARDWARE_UB,
};

enum class Position : int32_t {
  POSITION_GM,
  POSITION_VECIN,
  POSITION_VECOUT,
};

struct MemAttr {
  int64_t tensor_id = -1;
  AllocType alloc_type = AllocType::ALLOC_TYPE_GLOBAL;
  Position position = Position::POSITION_GM;
  MemHardware hardware = MemHardware::MEM_HARDWARE_GM;
  std::vector<int64_t> buf_ids;
  std::string name;
};

struct MemQueueAttr {
  int64_t id = kIdNone;
  int64_t depth{-1};
  int64_t buf_num{-1};
  std::string name;
};

struct MemBufAttr {
  int64_t id = kIdNone;
  std::string name;
};

struct MemOptAttr {
  int64_t reuse_id = kIdNone;
  int64_t ref_tensor = kIdNone;
  int64_t merge_scope = kIdNone;
};
struct AscNodeOutputs;
class AscTensorDataType {
 public:
  operator ge::DataType() const {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(tensor_desc_);
    return tensor_desc_->GetDataType();
  };
 private:
  friend struct AscNodeOutputs;
  GeTensorDesc *tensor_desc_;
};

class AscTensorFormat {
 public:
  operator ge::Format() const {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(tensor_desc_);
    return tensor_desc_->GetFormat();
  };
 private:
  friend struct AscNodeOutputs;
  GeTensorDesc *tensor_desc_;
};

struct AscTensorAttr : public ge::AttrGroupsBase {
  AscTensorDataType dtype;
  AscTensorFormat format;
  std::vector<int64_t> axis;
  std::vector<ge::expression::ExpressionPtr> repeats;
  std::vector<ge::expression::ExpressionPtr> strides;
  std::vector<int64_t> vectorized_axis;
  std::vector<ge::expression::ExpressionPtr> vectorized_strides;
  MemAttr mem;
  MemQueueAttr que;
  MemBufAttr buf;
  MemOptAttr opt;
  AttrGroupsBase *CreateNew() override;
  static AscTensorAttr &GetTensorAttr(ge::Operator *op, const uint32_t index);
};
void AddEdgeForNode(ge::Operator &src_op, int32_t src_index, ge::Operator &dst_op,
                    int32_t dst_index);

class AscOutputAttrDataType {
 public:
  AscOutputAttrDataType(ge::Operator *op, uint32_t output_index) : op_(op), output_index_(output_index) {}

  void operator=(const ge::DataType &value) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_);
    const auto desc = ge::OpDescUtils::GetOpDescFromOperator(*op_);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc->MutableOutputDesc(output_index_));
    desc->MutableOutputDesc(output_index_)->SetDataType(value);
  }

  operator ge::DataType() const {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_);
    const auto desc = ge::OpDescUtils::GetOpDescFromOperator(*op_);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc->MutableOutputDesc(output_index_));
    return desc->MutableOutputDesc(output_index_)->GetDataType();
  };

 private:
  ge::Operator *op_;
  uint32_t output_index_{UINT32_MAX};
};

class AscOutputAttrFormat {
 public:
  AscOutputAttrFormat(ge::Operator *op, uint32_t output_index) : op_(op), output_index_(output_index) {}

  void operator=(const ge::Format &value) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_);
    const auto desc = ge::OpDescUtils::GetOpDescFromOperator(*op_);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc->MutableOutputDesc(output_index_));
    desc->MutableOutputDesc(output_index_)->SetFormat(value);
  }

  operator ge::Format() const {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_);
    const auto desc = ge::OpDescUtils::GetOpDescFromOperator(*op_);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc->MutableOutputDesc(output_index_));
    return desc->MutableOutputDesc(output_index_)->GetFormat();
  };

 private:
  ge::Operator *op_{};
  uint32_t output_index_{UINT32_MAX};
};

struct AscOpOutput {
 public:
  class AscOpOutputOffsetHelper {
   public:
    explicit AscOpOutputOffsetHelper(AscOpOutput &output) : output_(output) {}
    ~AscOpOutputOffsetHelper() = default;
    void operator=(const AscOpOutput &asc_op_output) {
      CHECK_NOTNULL_WITH_THROW_EXCEPTION(asc_op_output.op_);
      output_.op_ = asc_op_output.op_;
      output_.output_index = asc_op_output.output_index;
      output_.dtype = asc_op_output.dtype;
      output_.format = asc_op_output.format;
      output_.axis = asc_op_output.axis;
      output_.repeats = asc_op_output.repeats;
      output_.strides = asc_op_output.strides;
      *asc_op_output.vectorized_axis = output_.load_vectorized_axes_;
      output_.vectorized_axis = asc_op_output.vectorized_axis;
      output_.mem = asc_op_output.mem;
      output_.que = asc_op_output.que;
      output_.buf = asc_op_output.buf;
      output_.opt = asc_op_output.opt;
    }
   private:
    AscOpOutput &output_;
  };
  template<uint32_t INPUT_INDEX>
  friend
  class AscOpInput;
  friend class VectorizedOutTensor;
  AscOpOutput(ge::Operator *op, uint32_t output_index)
      : op_(op), output_index(output_index), dtype(op, output_index), format(op, output_index),
        axis(&AscTensorAttr::GetTensorAttr(op, output_index).axis),
        repeats(&AscTensorAttr::GetTensorAttr(op,
                                              output_index).repeats),
        strides(&AscTensorAttr::GetTensorAttr(op,
                                              output_index).strides),
        vectorized_axis(&AscTensorAttr::GetTensorAttr(op,
                                                      output_index).vectorized_axis),
        mem(&AscTensorAttr::GetTensorAttr(op, output_index).mem),
        que(&AscTensorAttr::GetTensorAttr(op, output_index).que),
        buf(&AscTensorAttr::GetTensorAttr(op, output_index).buf),
        opt(&AscTensorAttr::GetTensorAttr(op, output_index).opt) {}
  explicit AscOpOutput(std::vector<int64_t> axes)
      : op_(nullptr), load_vectorized_axes_(std::move(axes)), output_index(0), dtype(nullptr, output_index),
        format(nullptr, output_index), repeats(nullptr), strides(nullptr), vectorized_axis(nullptr), mem(nullptr),
        que(nullptr), buf(nullptr), opt(nullptr) {}
  AscOpOutput(const AscOpOutput &output) : AscOpOutput(output.op_, output.output_index) {}
  AscOpOutput(AscOpOutput &&output)  noexcept : AscOpOutput(output.op_, output.output_index) {}
  AscOpOutput &operator=(const AscOpOutput &input) = delete;
  AscOpOutput &operator=(AscOpOutput &&) = delete;

  void SetContiguousView(const std::vector<Axis> &axes) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(axis, "output tensor should bind to API by API function or by AutoOffset");
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(repeats, "output tensor should bind to API by API function or by AutoOffset");
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(strides, "output tensor should bind to API by API function or by AutoOffset");
    std::vector<AxisId> axes_ids;
    std::vector<ge::expression::ExpressionPtr> tmp_repeats;
    std::vector<ge::expression::ExpressionPtr> tmp_strides;
    axes_ids.reserve(axes.size());
    tmp_repeats.reserve(axes.size());
    tmp_strides.reserve(axes.size());

    std::for_each(axes.rbegin(), axes.rend(),
                  [&axes_ids, &tmp_repeats, &tmp_strides](const Axis &tmp_axis) {
                    if (tmp_strides.empty()) {
                      tmp_strides.emplace_back(ge::expression::Expression::CreateExpression(1));
                    } else {
                      tmp_strides.emplace_back(*tmp_repeats.rbegin() * *tmp_strides.rbegin());
                    }
                    tmp_repeats.emplace_back(tmp_axis.size);
                    axes_ids.emplace_back(tmp_axis.id);
                  });
    std::reverse(axes_ids.begin(), axes_ids.end());
    std::reverse(tmp_repeats.begin(), tmp_repeats.end());
    std::reverse(tmp_strides.begin(), tmp_strides.end());

    *axis = axes_ids;
    *repeats = tmp_repeats;
    *strides = tmp_strides;
  }

  const ge::Operator &GetOwnerOp() const {
    return *op_;
  }

  ge::Operator &MutableOwnerOp() {
    return *op_;
  }

  AscOpOutput &Use(const AscOpOutput &used_out) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_, "output tensor should bind to API by API function or by AutoOffset");
    CHECK_BOOL_WITH_THROW_EXCEPTION(PARAM_INVALID, !HasBindToContainer(),
                                    " this tensor has been bound to a que or buf, can not be repeated bound.");
    CHECK_BOOL_WITH_THROW_EXCEPTION(PARAM_INVALID, used_out.HasBindToContainer(),
                                    " tensor to be used has not been bound to any que or buf.");
    if (used_out.que->id != kIdNone) {
      UseTQue(used_out.mem->position, used_out.que->depth, used_out.que->buf_num, used_out.que->id);
    }
    if (used_out.buf->id != kIdNone) {
      UseTBuf(used_out.mem->position, used_out.buf->id);
    }
    return *this;
  }

  AscOpOutput &TQue(const Position pos, const int64_t depth, const int64_t buf_num) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_, "output tensor should bind to API by API function or by AutoOffset");
    UseTQue(pos, depth, buf_num);
    return *this;
  }

  AscOpOutput &TBuf(const Position pos) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_, "output tensor should bind to API by API function or by AutoOffset");
    UseTBuf(pos);
    return *this;
  }
  AscOpOutputOffsetHelper AutoOffset() {
    return AscOpOutputOffsetHelper(*this);
  }

 private:
  int64_t GenContainerId();
  void UseTQue(const Position pos, const int64_t depth, const int64_t buf_num, const int64_t id = kIdNone);
  void UseTBuf(const Position pos, const int64_t id = kIdNone);
  bool HasBindToContainer() const;
  ge::Operator *op_;
  std::vector<int64_t> load_vectorized_axes_;
 public:
  uint32_t output_index{UINT32_MAX};
  AscOutputAttrDataType dtype;
  AscOutputAttrFormat format;
  std::vector<int64_t> *axis;
  std::vector<ge::expression::ExpressionPtr> *repeats;
  std::vector<ge::expression::ExpressionPtr> *strides;
  std::vector<int64_t> *vectorized_axis;
  MemAttr *mem;
  MemQueueAttr *que;
  MemBufAttr *buf;
  MemOptAttr *opt;
};

class VectorizedOutTensor {
 public:
  explicit VectorizedOutTensor(std::vector<int64_t> vectorized_axis) : vectorized_axis_(std::move(vectorized_axis)) {
  }
  VectorizedOutTensor &operator=(const VectorizedOutTensor &) = delete;
  VectorizedOutTensor(const VectorizedOutTensor &) = delete;
  explicit operator AscOpOutput() const {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_);
    return AscOpOutput(op_, output_index_);
  }
  void operator=(AscOpOutput &&asc_op_output) {
    // 不支持更改归属
    if (op_ != nullptr) {
      AscendString name;
      ASCIR_ASSERT_GRAPH_SUCCESS(op_->GetName(name));
      GELOGE(FAILED, "Tensor has been bind to %s", name.GetString());
      return;
    }
    op_ = asc_op_output.op_;
    output_index_ = asc_op_output.output_index;
    // 修改归属op的向量化轴信息
    AscTensorAttr::GetTensorAttr(op_, output_index_).vectorized_axis = vectorized_axis_;
  }
 private:
  std::vector<int64_t> vectorized_axis_;
  ge::Operator *op_{nullptr};
  uint32_t output_index_{UINT32_MAX};
};

template<uint32_t INPUT_INDEX>
class AscOpInput {
 public:
  explicit AscOpInput(ge::Operator *op) : op_(op) {}

  AscOpInput<INPUT_INDEX> &operator=(const AscOpOutput &output) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(output.op_);
    op_->SetInput(INPUT_INDEX, *output.op_, output.output_index);
    AddEdgeForNode(*output.op_, output.output_index, *op_, INPUT_INDEX);
    return *this;
  }

 private:
  ge::Operator *op_;
};
struct AscNodeOutputs {
  explicit AscNodeOutputs(const ge::OpDescPtr &op_desc);
  AscTensorAttr &operator[](uint32_t index);
  std::vector<AscTensorAttr *> operator()();
 private:
  ge::OpDescPtr op_desc_;
};

struct AscNodeInputs {
  explicit AscNodeInputs(ge::Node *node);
  AscTensorAttr &operator[](uint32_t index);
  uint32_t Size();
 private:
  ge::Node *node_;
};

class AscNode : public Node {
 public:
  AscNode(const OpDescPtr &op_desc, const ComputeGraphPtr &compute_graph);
  AscNodeInputs inputs;
  AscNodeOutputs outputs;
  AscNodeAttr &attr;
};
using AscNodePtr = std::shared_ptr<AscNode>;

class AscNodeIter {
 public:
  explicit AscNodeIter(ge::ComputeGraph::Vistor<ge::NodePtr>::Iterator &&iter);
  AscNodeIter &operator++();
  AscNodePtr operator*();
  bool operator!=(const AscNodeIter &other) const;
 private:
  ge::ComputeGraph::Vistor<ge::NodePtr>::Iterator impl_;
};

class AscNodeVisitor {
 public:
  using Iterator = ge::ComputeGraph::Vistor<ge::NodePtr>::Iterator;
  AscNodeIter begin();
  AscNodeIter end();
  explicit AscNodeVisitor(ge::ComputeGraph::Vistor<ge::NodePtr> &&visitor);
 private:
  ge::ComputeGraph::Vistor<ge::NodePtr> impl_;
};

class AscGraphImpl;
namespace ascir {
namespace cg {
class CodeGenUtils;
}
}
class AscGraph {
  friend class ascir::cg::CodeGenUtils;
 public:
  explicit AscGraph(const char *name);
  ~AscGraph();
  void SetTilingKey(const uint32_t tiling_key);
  int64_t GetTilingKey() const;
  Axis &CreateAxis(const std::string &name, const ge::expression::ExpressionPtr &size,
                   const int64_t min_value = -1, const int64_t max_value = -1);
  Axis *FindAxis(const int64_t axis_id);
  Optional &CreateOptionalAtt(const std::string &name, uint32_t idx, int32_t min_value, int32_t max_value);
  Optional &CreateOptionalAtt(const std::string &name, uint32_t idx, uint32_t min_value, uint32_t max_value);
  Optional &CreateOptionalAtt(const std::string &name, uint32_t idx, float min_value, float max_value);
  Optional &CreateOptionalAtt(const std::string &name, uint32_t idx, int8_t min_value, int8_t max_value);
  Optional &CreateOptionalAtt(const std::string &name, uint32_t idx, const std::string &data_type,
                              const std::string &min_value, const std::string &max_value);
  void AddNode(ge::Operator &op);
  AscNodePtr FindNode(const char *name) const;
  AscNode &Node(const char *name) const;
  std::pair<AxisPtr, AxisPtr> BlockSplit(const int64_t axis_id, const std::string &outer_axis_name = "",
                                         const std::string &inner_axis_name = "");
  std::pair<AxisPtr, AxisPtr> TileSplit(const int64_t axis_id, const std::string &outer_axis_name = "",
                                        const std::string &inner_axis_name = "");
  AxisPtr MergeAxis(const std::vector<int64_t> &axis_ids, const std::string &merge_axis_name = "");
  void ApplySplit(const AscNodePtr &node, const int64_t outter_id, const int64_t inner_id);
  void ApplyMerge(const AscNodePtr &node, const int64_t merged_axis_id);
  void ApplyReorder(const AscNodePtr &node, const std::vector<int64_t> &reordered_axis);
  AscNodeVisitor GetAllNodes() const;
  AscNodeVisitor GetInputNodes() const;
  std::vector<AxisPtr> GetAllAxis() const;
  std::vector<OptionalPtr> GetAllOptional() const;
  TransInfoRoadOfGraph GetAllAxisTransInfo() const;
  std::string GetName() const;
  bool CheckValid() const;
  AscOpOutput CreateContiguousData(const char *name,
                                   const ge::DataType &dt,
                                   const std::vector<ge::Axis> &axes,
                                   const std::vector<std::vector<int64_t>> &axis_continuous_map,
                                   const ge::Format &format = ge::FORMAT_ND);

  AscOpOutput CreateContiguousData(const char *name,
                                   const ge::DataType &dt,
                                   const std::vector<ge::Axis> &axes,
                                   const ge::Format &format = ge::FORMAT_ND);

  AscOpOutput CreateContiguousOut(const char *name,
                                  const ge::DataType &dt,
                                  const std::vector<ge::Axis> &axes,
                                  const ge::Format &format = ge::FORMAT_ND);
 private:
  bool CheckExprValid() const;
  bool CheckAxisValid() const;
  bool CheckExecOrderValid() const;
  bool CheckTensorValid() const;
  bool CheckNodeConnectionValid() const;
  std::shared_ptr<AscGraphImpl> impl_;
};
}  // namespace ge

#endif  // GRAPH_ASCEND_IR_H
